#include "i2clang.h"

#include "debug.h"


int next_hex( char *p )
{
	if (p==NULL) return -1;
	//printf("%s\n",p);
	if ((p[0] == '0') && (p[1] == 'x')) return 0;
	return -1;
}


int next_bin( char *p )
{
	if (p==0) return -1;
	//printf("%s\n",p);
	if ((p[0] == '0') && (p[1] == 'b')) return 0;
	return -1;
}


int add_new_byte( op *o, uint8_t val )
{
	o->data = realloc( o->data, o->size+1 );
	o->data[o->size] = val;
	o->size += 1;
	return 0;
}


op* i2clang( int argc, char **argv )
{
	int      cnt       = 1;
	int      lcnt      = 0;
	int      cur_op;
	//int      data_size = 0;
	//uint8_t *data_cur  = NULL;
	op      *ops       = NULL;
	int     cnt_ops    = 0;
	op      t_op;
	char    *p         = NULL;
	//set initial bus-0 and addr-0

	ops = malloc( sizeof(op)*(MAX_OP_STACK+1) );
	if ( ops == NULL )
	{
		printf("Cannot allocate operation stack\n");
		return NULL;
	}
	memset( ops, 0, sizeof(op)*(MAX_OP_STACK+1) );
	memset( &t_op, 0, sizeof(t_op) );

//-----------------------------------------------------------------------------
state_start:
	dbgs("START");
	p = argv[cnt];
	if ( p == NULL ) goto state_end;
	printf("%20s\n",p);
	switch ( p[0] )
	{

		case 'r':
			goto state_read;
		case 'w':
			goto state_write;
		case 'b':
			goto state_bus;
		case 'a':
			goto state_addr;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_read:
	dbgs("READ");
	cnt++; if (cnt>argc) goto state_end; p = argv[cnt]; cur_op = OP_READ;
	t_op.op = OP_READ;
	printf("%20s\n",p);
	switch ( p[0] )
	{
		case '0':
			if ( p[1] == 'x' )
			{
				goto state_hex;
			} else if ( p[1] == 'b' )
			{
				goto state_binary;
			}
			goto state_error;
		case 'a':
			goto state_all;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_write:
	dbgs("WRITE");
	cnt++; if (cnt>argc) goto state_end; p = argv[cnt]; cur_op = OP_WRITE;
	t_op.op = OP_WRITE;
	switch ( p[0] )
	{
		case '0':
			if ( p[1] == 'x' )
			{
				goto state_hex;
			} else if ( p[1] == 'b' )
			{
				goto state_binary;
			}
			goto state_error;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_bus:
	dbgs("BUS");
	cnt++; if (cnt>argc) goto state_end; p = argv[cnt]; cur_op = OP_BUS;
	t_op.op = OP_BUS;
	switch ( p[0] )
	{
		case '0':
			if ( p[1] == 'x' )
			{
				goto state_hex;
			} else if ( p[1] == 'b' )
			{
				goto state_binary;
			}
			goto state_error;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_addr:
	dbgs("ADDR");
	cnt++; if (cnt>argc) goto state_end; p = argv[cnt]; cur_op = OP_ADDR;
	t_op.op = OP_ADDR;
	
	switch ( p[0] )
	{
		case '0':
			if ( p[1] == 'x' )
			{
				goto state_hex;
			} else if ( p[1] == 'b' )
			{
				goto state_binary;
			}
			goto state_error;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_next:
	dbgs("NEXT");
	cnt++;
	if ( t_op.op != OP_NONE)
	{
		if ( cnt_ops < MAX_OP_STACK )
		{
			memcpy( &ops[cnt_ops], &t_op, sizeof(t_op) );
			cnt_ops++;
		}
	}
	memset( &t_op, 0, sizeof(t_op) );
	goto state_start;
	goto state_error;

//-----------------------------------------------------------------------------
state_binary:
	dbgs("BIN");
	
	p = argv[cnt];
	lcnt = 2;
	while ( (p[lcnt] == '1') || (p[lcnt] == '0') )
	{
		lcnt++;
	}
	if (p[lcnt] != 0x0 )
		goto state_error;

	switch ( cur_op )
	{
		case OP_BUS:
			goto state_next;
		case OP_ADDR:
			goto state_next;
		case OP_READ:
			goto state_next;
		case OP_WRITE:
			if (next_hex(argv[cnt+1])==0) {cnt++;goto state_hex;}
			if (next_bin(argv[cnt+1])==0) {cnt++;goto state_binary;}
			goto state_next;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_hex:
	dbgs("HEX");

	p = argv[cnt];
	lcnt = 2;
	while ( ((p[lcnt]>='0') && (p[lcnt]<='9')) || 
		((p[lcnt]>='a') && (p[lcnt]<='f')) )
	{
		lcnt++;
	}
	if ( p[lcnt] != 0x0 )
		goto state_error;

	printf("hex=%s\n",p);
	
	{
		uint32_t v;
		sscanf( p, "0x%x", &v );
		add_new_byte( &t_op, v );
	}
	
	switch ( cur_op )
	{
		case OP_BUS:
			goto state_next;
		case OP_ADDR:
			goto state_next;
		case OP_READ:
			goto state_next;
		case OP_WRITE:
			if (next_hex(argv[cnt+1])==0) {cnt++;goto state_hex;}
			if (next_bin(argv[cnt+1])==0) {cnt++;goto state_binary;}
			goto state_next;
	}
	goto state_error;


//-----------------------------------------------------------------------------
state_all:
	dbgs("ALL");
	t_op.op = OP_READALL;
	goto state_next;
	goto state_error;


//-----------------------------------------------------------------------------
state_error:
	dbgs("ERR");

//-----------------------------------------------------------------------------
state_end:
	dbgs("END");

	return ops;
}

